package monsmon.util.getopt;

import java.util.*;

public class Getopt{

	private String argv[];
	private String opts;
	private LongOpt[] lopts;

	private int idx = 0;
	private String copt, carg;

	private char dec_opt[];
	private byte need_arg[];

	private String long_opts_dec[];

	private List<String> ex_args = new ArrayList<String>();

	private static final byte 
		NONE	= LongOpt.NO_ARG,
		OPTA	= LongOpt.OPT_ARG,
		NEED	= LongOpt.REQ_ARG;

	public Getopt(String argv[], String opts){
		this(argv, opts, new LongOpt[]{});
	}

	public Getopt(String argv[], String opts, LongOpt[] lopts){
		this.argv = argv;
		this.opts = opts;
		this.lopts = lopts;
		compile_opts(opts);
	}

	private void compile_opts(String o){
		char c = 0;
		int k = 0;
		int numopts = 0;
		for(int i = 0; i < o.length(); i++){
			if(opts.charAt(i) != ':'){
				numopts++;
			}
		}
		dec_opt = new char[numopts];
		need_arg = new byte[numopts];
		for(int i = 0; i < o.length(); i++){
			dec_opt[k] = o.charAt(i);
			if(i + 2 < o.length() && o.charAt(i + 1) == ':' 
					&& o.charAt(i + 2) == ':'){
				need_arg[k] = OPTA;
				i += 2;
			}else if(i + 1 < o.length() && o.charAt(i + 1) == ':'){
				need_arg[k] = NEED;
				i++;
			}else{
				need_arg[k] = NONE;
			}
			k++;
		}
	}

	//Returns the opt num of the current option
	//Returns '?' on an unknown argument
	//	   -1 on a completion
	//	   ':' on a missing argument
	public int getopt(){
		copt = null;
		carg = null;
		if(idx >= argv.length) return -1;
		String a = argv[idx];
		copt = a;
		if(a.charAt(0) != '-'){
			//Its an arg
			idx++;
			ex_args.add(a);
			return getopt();
		}else if (a.length() >= 2){
			int k = 0;
			boolean found = false;
			int c = 0;
			//Parse long options
			if(a.charAt(1) == '-'){
				a = a.substring(2);
				for(k = 0; k < lopts.length; k++){
					if(a.equals(lopts[k].name)){
						found = true;
						break;
					}
				}
				if(!found) {idx++; return '?'; }
				c = lopts[k].val;
				if(lopts[k].has_arg == NEED){
					if(argv.length > idx + 1 &&
						argv[idx+1].length() > 1 && 
						argv[idx+1].charAt(0) != '-'){
						carg = argv[idx+1];
						idx++;
					}else{
						c = ':';
					}
				}else if(lopts[k].has_arg == OPTA){
					if(argv.length > idx + 1 && 
						argv[idx+1].length() > 1 &&
						argv[idx+1].charAt(0) != '-'){
						carg = argv[idx+1];
						idx++;
					}
				}
				idx++;
				return c;
			}
			//Regular options
			 c = a.charAt(1);
			for(; k < dec_opt.length; k++){
				if(dec_opt[k] == c){
					found = true;
					break;
				}
			}
			if(!found) {idx++; return '?'; } 
			if(need_arg[k] == NEED){
				if(argv.length > idx + 1 &&
					argv[idx+1].length() > 1 && 
					argv[idx+1].charAt(0) != '-'){
					carg = argv[idx+1];
					idx++;
				}else{
					c = ':';
				}
			}else if(need_arg[k] == OPTA){
				if(argv.length > idx + 1 && 
					argv[idx+1].length() > 1 &&
					argv[idx+1].charAt(0) != '-'){
					carg = argv[idx+1];
					idx++;
				}
			}
			idx++;
			return c;
		}else{
			idx++;
			return '?';
		}
	}

	public String get_optarg(){
		return carg;
	}

	public String get_optopt(){
		return copt;
	}

	public List<String> get_args(){
		return ex_args;
	}


}
